package cn.rocksolid.sport.assist.sms;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;

import javax.annotation.PreDestroy;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;

import cn.rocksolid.sport.assist.entity.SmsEntity;
import cn.rocksolid.sport.common.Constant.SmsProviderType;
import cn.rocksolid.sport.common.error.RSE;
import cn.rocksolid.sport.common.error.RockSolidException;
import cn.rocksolid.sport.common.task.ExecutorServiceUtils;
import cn.rocksolid.sport.common.utils.AssertUtils;

public class AliYunSmsProvider extends AbstractSmsProvider implements SmsProvider {

  private static final String SMS_ACTION = "SendSms";

  private static final String DEFAULT_VERSION = "2017-05-25";
  private static final String DEFAULT_DOMAIN = "dysmsapi.aliyuncs.com";
  private static final String DEFAULT_REGION_ID = "default";

  private static final int LIMIT_COUNT_OF_MOBILES_OF_SMS = 1000;

  private static final String CFG_REGION_ID = "region-id";
  private static final String CFG_ACCESS_KEY_ID = "access-key-id";
  private static final String CFG_ACCESS_SECRET = "access-secret";

  private static final String P_SIGN_NAME = "SignName";
  private static final String P_TEMPLATE_CODE = "TemplateCode";
  private static final String P_TEMPLATE_PARAM = "TemplateParam";
  private static final String P_PHONE_NUMBERS = "PhoneNumbers";
  private static final String PHONE_NUMBERS_SEPARATOR = ",";

  private final ExecutorService es = ExecutorServiceUtils.init();

  @PreDestroy
  public void destroy() {
    ExecutorServiceUtils.destroy(es);
  }

  public AliYunSmsProvider(Map<String, String> config) {
    super(config);
    if (MapUtils.isEmpty(config) || StringUtils.isBlank(config.get(CFG_ACCESS_KEY_ID))
        || StringUtils.isBlank(config.get(CFG_ACCESS_SECRET))) {
      throw new RockSolidException(RSE.INVALID_SMSP_CONF);
    }
  }

  @Override
  public SmsProviderType getType() {
    return SmsProviderType.ALIYUN;
  }

  @Override
  public void sendSms(SmsEntity smsEntity, String... extraParams) {
    check(smsEntity);
    es.submit(new Callable<Void>() {
      @Override
      public Void call() throws Exception {
        try {
          DefaultProfile aliyunSmsProfile = DefaultProfile.getProfile(
              config.getOrDefault(CFG_REGION_ID, DEFAULT_REGION_ID), config.get(CFG_ACCESS_KEY_ID),
              config.get(CFG_ACCESS_SECRET));
          IAcsClient smsClient = new DefaultAcsClient(aliyunSmsProfile);
          CommonRequest req = new CommonRequest();
          req.setSysMethod(MethodType.POST);
          req.setSysVersion(DEFAULT_VERSION);
          req.setSysDomain(DEFAULT_DOMAIN);
          req.setSysAction(SMS_ACTION);
          req.putQueryParameter(P_SIGN_NAME, extraParams[0]);
          req.putQueryParameter(P_TEMPLATE_CODE, smsEntity.getTemplateCode());
          req.putQueryParameter(P_PHONE_NUMBERS, String.join(PHONE_NUMBERS_SEPARATOR, smsEntity.getMobiles()));
          req.putQueryParameter(P_TEMPLATE_PARAM, JSON.toJSONString(smsEntity.getParameters()));
          smsClient.getCommonResponse(req);
        } catch (Exception exp) {
          throw new RockSolidException(RSE.RS_TASK_FAIL, exp);
        }
        return null;
      }
    });
  }

  private void check(SmsEntity smsEntity) {
    AssertUtils.isNotNull(smsEntity, RSE.INVALID_PAYLOAD);
    if (CollectionUtils.isEmpty(smsEntity.getMobiles())
        || smsEntity.getMobiles().size() > LIMIT_COUNT_OF_MOBILES_OF_SMS) {
      throw new RockSolidException(RSE.INVALID_SMS_MOBILES);
    }
    if (MapUtils.isEmpty(smsEntity.getParameters())) {
      throw new RockSolidException(RSE.INVALID_SMS_PARAMS);
    }
  }
}
